﻿namespace Trading.Studio

open System
open System.ComponentModel
open System.Collections.Generic
open Castle.Core.Interceptor
open Castle.DynamicProxy

type ViewModel() = 
    let propertyChangedEvent = new DelegateEvent<PropertyChangedEventHandler>()
    let errors = new Dictionary<string, string>()
    static let proxyFactory = ProxyGenerator()

    interface INotifyPropertyChanged with
        [<CLIEvent>]
        member x.PropertyChanged = propertyChangedEvent.Publish

    member this.OnPropertyChanged propertyName = 
        propertyChangedEvent.Trigger([| this; PropertyChangedEventArgs(propertyName) |])

    interface IDataErrorInfo with
        member this.Error = raise <| NotImplementedException()
        member this.Item 
            with get(propertyName) = 
                match errors.TryGetValue propertyName with
                | true, error -> error
                | false, _ -> ""

    member this.SetPropertyError(propertyName, message) = 
        errors.[propertyName] <- message
        this.OnPropertyChanged propertyName

    static member Create<'T when 'T :> ViewModel and 'T : not struct>() : 'T =
        proxyFactory.CreateClassProxy(PropSetterInterceptor())
        
and PropSetterInterceptor() =  
    interface IInterceptor with
        member this.Intercept(invocation) = 
            invocation.Proceed()
            match invocation.Method.Name.Split('_') with 
                | [| "set"; propertyName |] ->
                    assert invocation.Method.IsSpecialName
                    let viewModel = invocation.InvocationTarget :?> ViewModel
                    viewModel.OnPropertyChanged propertyName
                | _ -> ()


